/*
 * Copyright (C) 2010 TopCoder Inc., All Rights Reserved.
 */
package com.hercules.android.receiver.commands;

import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import com.hercules.android.receiver.Config;
import com.hercules.android.receiver.Receiver;
import com.hercules.android.receiver.ReceiverUtil;
import com.hercules.android.receiver.XREObjectFormatterException;
import com.hercules.android.receiver.entities.XREObject;
import com.hercules.android.receiver.entities.XREView;

/**
 * <p>
 * This command handler class will handle the NEW command.
 * </p>
 * 
 * @author TCSASSEMBER
 * @version 1.0
 */
public class XRENewCommandHandler extends XRECommandHandler {
    /**
     * Represents the mapping from klass of XRE resource to the corresponding
     * <code>XREObject</code> class.
     */
    private Map<String, Class<? extends XREObject>> klassObjects;

    /**
     * Create a new <code>XRENewCommandHandler</code> with the
     * <code>Receiver</code> instance and the mapping from klass of XRE resource
     * to the corresponding <code>XREObject</code> class.
     * 
     * @param receiver
     *            the <code>Receiver</code> instance.
     * @param klassObjects
     *            the mapping from klass of XRE resource to the corresponding
     *            <code>XREObject</code> class.
     * @throws IllegalArgumentException
     *             if arguments is null
     */
    public XRENewCommandHandler(Receiver receiver, Map<String, Class<? extends XREObject>> klassObjects) {
        super(receiver);

        ReceiverUtil.checkNull("klassObjects", klassObjects);

        this.klassObjects = klassObjects;
    }

    /**
     * Process the NEW command message.
     * 
     * @param message
     *            the command message to be processed.
     * @throws XRECommandHandlerException
     *             if any other error occurs
     */
    public void processCommand(JSONObject message) throws XRECommandHandlerException {
        try {
            String klass = message.getString("klass");
            Class<? extends XREObject> clazz = klassObjects.get(klass);
            if (clazz == null) {
                return;
                //throw new XRECommandHandlerException("Klass [" + klass + "] can't be recognized.");
            }
            XREObject object = clazz.newInstance();
            object.setProperties(message);

            receiver.getApplicationData().getElementsXREIdToElement().put(object.getId(), object);
            if (object.getKlass().equals("XREView")) {
                XREView view = (XREView) object;
                if (view.getParent() > 0) {
                    XREObject parent = receiver.getApplicationData().getElementsXREIdToElement().get(view.getParent());
                    if (!(parent instanceof XREView)) {
                        throw new XRECommandHandlerException("Parent object [" + view.getParent() + "] is not XREView.");
                    }
                    ((XREView) parent).getChildren().add(view);
                }
            }
        } catch (JSONException e) {
            throw new XRECommandHandlerException("Error occurs when reading from json.", e);
        } catch (InstantiationException e) {
            throw new XRECommandHandlerException("Can't create new XREObject instance.", e);
        } catch (IllegalAccessException e) {
            throw new XRECommandHandlerException("Can't create new XREObject instance.", e);
        } catch (XREObjectFormatterException e) {
            throw new XRECommandHandlerException("Can't set properties to XREObject.", e);
        }
    }

    /**
     * This method will return a flag indicates whether the canvas need to be
     * updated after the command message was processed.
     * 
     * @param message
     *            the command message.
     * @return true if the canvas need to be updated after the command message
     *         was processed, false otherwise
     */
    public boolean needRedraw(JSONObject message) {
        try {
            String klass = message.getString("klass");
            if (Config.XRE_KLASS_VIEW.equals(klass)) {
                int id = message.getInt("id");
                XREView view = (XREView) receiver.getApplicationData().getElementsXREIdToElement().get(id);
                if (view.getResource() > 0) {
                    return true;
                }
            }
        } catch (JSONException e) {
            // ignore
        }
        return false;
    }
}
